package com.dd.keel.core.loader.bootstrap;

import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.lang.reflect.Array;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.Properties;
import java.util.Iterator;

import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;

/**
 * Bootstrap Main Class
 * @author Kevin.XU
 *
 */
public class Bootstrap {

	protected static final String KEEL_HOME_TOKEN = "${keel.home}";
    
    protected ClassLoader commonLoader = null;
    protected ClassLoader serverLoader = null;
    protected ClassLoader sharedLoader = null;
	
	
    private ClassLoader createClassLoader(String name, ClassLoader parent) throws Exception {

		String value = JackeelProperties.getProperty(name + ".loader");
		
		if ((value == null) || (value.equals("")))
			return parent;

		ArrayList repositoryLocations = new ArrayList();
		ArrayList repositoryTypes = new ArrayList();
		int i;

		StringTokenizer tokenizer = new StringTokenizer(value, ",");
		while (tokenizer.hasMoreElements()) {
			String repository = tokenizer.nextToken();

			// Local repository
			boolean replace = false;
			String before = repository;
			while ((i = repository.indexOf(KEEL_HOME_TOKEN)) >= 0) {
				replace = true;
				if (i > 0) {
					repository = repository.substring(0, i)
							+ JackeelProperties.getJackeelHome()
							+ repository.substring(i
									+ KEEL_HOME_TOKEN.length());
				} else {
					repository = JackeelProperties.getJackeelHome()
							+ repository
									.substring(KEEL_HOME_TOKEN.length());
				}
			}

			// Check for a JAR URL repository
			try {
				URL url = new URL(repository);
				repositoryLocations.add(repository);
				repositoryTypes.add(ClassLoaderFactory.IS_URL);
				continue;
			} catch (MalformedURLException e) {
				// Ignore
			}

			if (repository.endsWith("*.jar")) {
				repository = repository.substring(0, repository.length() - "*.jar".length());
				repositoryLocations.add(repository);
				repositoryTypes.add(ClassLoaderFactory.IS_GLOB);
			} else if (repository.endsWith(".jar")) {
				repositoryLocations.add(repository);
				repositoryTypes.add(ClassLoaderFactory.IS_JAR);
			} else {
				repositoryLocations.add(repository);
				repositoryTypes.add(ClassLoaderFactory.IS_DIR);
			}
		}

		String[] locations = (String[]) repositoryLocations.toArray(new String[0]);
		Integer[] types = (Integer[]) repositoryTypes.toArray(new Integer[0]);

		ClassLoader classLoader = ClassLoaderFactory.createClassLoader(locations, types, parent);

		return classLoader;
	}
	
    private void initClassLoaders() {
        try {
            commonLoader = createClassLoader("common", null);
            if( commonLoader == null ) {
                // no config file, default to this loader - we might be in a 'single' env.
                commonLoader = this.getClass().getClassLoader();
            }
            serverLoader = createClassLoader("server", commonLoader);
            sharedLoader = createClassLoader("shared", serverLoader);
        } catch (Throwable t) {
            System.exit(1);
        }
    }
    
    public void init(String args[]) throws Exception
    {
    	
    	initClassLoaders();
    	
    	Thread.currentThread().setContextClassLoader(sharedLoader);
    	
    	//load startup class
    	String startup_class_name = JackeelProperties.getProperty("entrance.class");
    	if(startup_class_name==null || startup_class_name.trim().equals(""))
    	{
    		System.out.println("'entrance.class' system property is ["+startup_class_name+"]");
    		System.out.println("You should set 'entrance.class' system property!");
    		System.exit(1);
    	}
    	Class startupClass = sharedLoader.loadClass( startup_class_name );
    	Object startupInstance = startupClass.newInstance();
    	
        String methodName = "entrance";
        Class paramTypes[] = new Class[1];
        paramTypes[0] = String[].class; //Class.forName("[Ljava.lang.String;");
        Object paramValues[] = new Object[1];
        paramValues[0] = Array.newInstance(String.class, args.length);
        for(int i=0; i<args.length; ++i)
        {
        	Array.set(paramValues[0], i, args[i]);
        }
        Method method = startupInstance.getClass().getMethod(methodName, paramTypes);
        method.invoke(startupInstance, paramValues);
        
    }
    
    
    public static void main(String args[]) throws Exception
    {
    	Bootstrap bootstrap = new Bootstrap();
    	bootstrap.init(args);
    }
    
    
}
